From 836c3ab043700e0c13fb63da00e76ac9851a6d4d Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Wed, 1 Jul 2009 10:32:26 +0200 Subject: [PATCH] Improve show_and_select_files() function The previous function enumerated the whole directory and used a lot of outdated API to decide how to show files. The new code queries the filesystem model to decide about this. The now unused old functions were removed. --- gtk/gtkfilechooserdefault.c | 248 ++++++------------------------------ gtk/gtkfilechooserprivate.h | 1 - gtk/gtkfilesystemmodel.c | 62 ++++++++- gtk/gtkfilesystemmodel.h | 2 + 4 files changed, 101 insertions(+), 212 deletions(-) diff --git a/gtk/gtkfilechooserdefault.c b/gtk/gtkfilechooserdefault.c index 1c7d93c218..dd835e9883 100644 --- a/gtk/gtkfilechooserdefault.c +++ b/gtk/gtkfilechooserdefault.c @@ -369,11 +369,6 @@ static void list_row_activated (GtkTreeView *tree_view, GtkTreeViewColumn *column, GtkFileChooserDefault *impl); -static void select_func (GtkFileSystemModel *model, - GtkTreePath *path, - GtkTreeIter *iter, - gpointer user_data); - static void path_bar_clicked (GtkPathBar *path_bar, GFile *file, GFile *child, @@ -5641,12 +5636,6 @@ gtk_file_chooser_default_dispose (GObject *object) impl->update_current_folder_cancellable = NULL; } - if (impl->show_and_select_files_cancellable) - { - g_cancellable_cancel (impl->show_and_select_files_cancellable); - impl->show_and_select_files_cancellable = NULL; - } - if (impl->should_respond_get_info_cancellable) { g_cancellable_cancel (impl->should_respond_get_info_cancellable); @@ -5866,52 +5855,6 @@ gtk_file_chooser_default_size_allocate (GtkWidget *widget, GTK_WIDGET_CLASS (_gtk_file_chooser_default_parent_class)->size_allocate (widget, allocation); } -static gboolean -get_is_file_filtered (GtkFileChooserDefault *impl, - GFile *file, - GFileInfo *file_info) -{ - GtkFileFilterInfo filter_info; - GtkFileFilterFlags needed; - gboolean result; - - if (!impl->current_filter) - return FALSE; - - filter_info.contains = GTK_FILE_FILTER_DISPLAY_NAME | GTK_FILE_FILTER_MIME_TYPE; - - needed = gtk_file_filter_get_needed (impl->current_filter); - - filter_info.display_name = g_file_info_get_display_name (file_info); - filter_info.mime_type = g_content_type_get_mime_type (g_file_info_get_content_type (file_info)); - - if (needed & GTK_FILE_FILTER_FILENAME) - { - filter_info.filename = g_file_get_path (file); - if (filter_info.filename) - filter_info.contains |= GTK_FILE_FILTER_FILENAME; - } - else - filter_info.filename = NULL; - - if (needed & GTK_FILE_FILTER_URI) - { - filter_info.uri = g_file_get_uri (file); - if (filter_info.uri) - filter_info.contains |= GTK_FILE_FILTER_URI; - } - else - filter_info.uri = NULL; - - result = gtk_file_filter_filter (impl->current_filter, &filter_info); - - g_free ((gchar *)filter_info.filename); - g_free ((gchar *)filter_info.uri); - g_free ((gchar *)filter_info.mime_type); - - return !result; -} - static void set_sort_column (GtkFileChooserDefault *impl) { @@ -6360,151 +6303,58 @@ browse_files_center_selected_row (GtkFileChooserDefault *impl) gtk_tree_selection_selected_foreach (selection, center_selected_row_foreach_cb, &closure); } -struct ShowAndSelectPathsData -{ - GtkFileChooserDefault *impl; - GSList *files; -}; - -static void -show_and_select_files_finished_loading (GtkFolder *folder, - gpointer user_data) +static gboolean +show_and_select_files (GtkFileChooserDefault *impl, + GSList *files) { - gboolean have_hidden; - gboolean have_filtered; - GSList *l; - struct ShowAndSelectPathsData *data = user_data; - - have_hidden = FALSE; - have_filtered = FALSE; - - for (l = data->files; l; l = l->next) - { - GFile *file; - GFileInfo *info; - - file = l->data; - - info = _gtk_folder_get_info (folder, file); - if (info) - { - if (!have_hidden) - have_hidden = g_file_info_get_is_hidden (info) - || g_file_info_get_is_backup (info); - - if (!have_filtered) - have_filtered = (! _gtk_file_info_consider_as_directory (info)) && - get_is_file_filtered (data->impl, file, info); - - g_object_unref (info); - - if (have_hidden && have_filtered) - break; /* we now have all the information we need */ - } - } - - g_signal_handlers_disconnect_by_func (folder, - show_and_select_files_finished_loading, - user_data); - - if (have_hidden) - g_object_set (data->impl, "show-hidden", TRUE, NULL); + GtkTreeSelection *selection; + GtkFileSystemModel *fsmodel; + gboolean can_have_hidden, can_have_filtered, selected_a_file; + GSList *walk; - if (have_filtered) - set_current_filter (data->impl, NULL); + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view)); + fsmodel = GTK_FILE_SYSTEM_MODEL (gtk_tree_view_get_model (GTK_TREE_VIEW (impl->browse_files_tree_view))); + can_have_hidden = !impl->show_hidden; + can_have_filtered = impl->current_filter != NULL; + selected_a_file = FALSE; - for (l = data->files; l; l = l->next) + for (walk = files; walk && (can_have_hidden || can_have_filtered); walk = walk->next) { - GFile *file; - GtkTreePath *path; + GFile *file = walk->data; GtkTreeIter iter; - file = l->data; - if (!_gtk_file_system_model_get_iter_for_file (data->impl->browse_files_model, - &iter, - file)) - return; - - path = gtk_tree_model_get_path (GTK_TREE_MODEL (data->impl->browse_files_model), &iter); - select_func (data->impl->browse_files_model, path, &iter, data->impl); - gtk_tree_path_free (path); - } - - browse_files_center_selected_row (data->impl); - - g_object_unref (data->impl); - g_slist_foreach (data->files, (GFunc) g_object_unref, NULL); - g_slist_free (data->files); - g_free (data); -} - -static void -show_and_select_files_get_folder_cb (GCancellable *cancellable, - GtkFolder *folder, - const GError *error, - gpointer user_data) -{ - gboolean cancelled = g_cancellable_is_cancelled (cancellable); - struct ShowAndSelectPathsData *data = user_data; - - if (data->impl->show_and_select_files_cancellable != cancellable) - goto out; - - data->impl->show_and_select_files_cancellable = NULL; - - if (cancelled || error) - goto out; - - g_object_unref (cancellable); - - if (_gtk_folder_is_finished_loading (folder)) - show_and_select_files_finished_loading (folder, user_data); - else - g_signal_connect (folder, "finished-loading", - G_CALLBACK (show_and_select_files_finished_loading), - user_data); - - return; - -out: - g_object_unref (data->impl); - g_slist_foreach (data->files, (GFunc) g_object_unref, NULL); - g_slist_free (data->files); - g_free (data); - - g_object_unref (cancellable); -} + if (!_gtk_file_system_model_get_iter_for_file (fsmodel, &iter, file)) + continue; -static gboolean -show_and_select_files (GtkFileChooserDefault *impl, - GFile *parent_file, - GSList *files) -{ - struct ShowAndSelectPathsData *info; + if (!_gtk_file_system_model_get_is_visible (fsmodel, &iter)) + { + GFileInfo *info = _gtk_file_system_model_get_info (fsmodel, &iter); - profile_start ("start", NULL); + if (can_have_hidden && + (g_file_info_get_is_hidden (info) || + g_file_info_get_is_backup (info))) + { + g_object_set (impl, "show-hidden", TRUE, NULL); + can_have_hidden = FALSE; + } - if (!files) - { - profile_end ("end", NULL); - return TRUE; + if (can_have_filtered) + { + set_current_filter (impl, NULL); + can_have_filtered = FALSE; + } + } + + if (_gtk_file_system_model_get_is_visible (fsmodel, &iter)) + { + gtk_tree_selection_select_iter (selection, &iter); + selected_a_file = TRUE; + } } - info = g_new (struct ShowAndSelectPathsData, 1); - info->impl = g_object_ref (impl); - info->files = g_slist_copy (files); - g_slist_foreach (info->files, (GFunc) g_object_ref, NULL); + browse_files_center_selected_row (impl); - if (impl->show_and_select_files_cancellable) - g_cancellable_cancel (impl->show_and_select_files_cancellable); - - impl->show_and_select_files_cancellable = - _gtk_file_system_get_folder (impl->file_system, parent_file, - "standard::is-hidden,standard::is-backup,standard::type,standard::name,standard::content-type", - show_and_select_files_get_folder_cb, info); - - profile_end ("end", NULL); - return TRUE; + return selected_a_file; } /* Processes the pending operation when a folder is finished loading */ @@ -6516,7 +6366,7 @@ pending_select_files_process (GtkFileChooserDefault *impl) if (impl->pending_select_files) { - show_and_select_files (impl, impl->current_folder, impl->pending_select_files); + show_and_select_files (impl, impl->pending_select_files); pending_select_files_free (impl); browse_files_center_selected_row (impl); } @@ -7380,20 +7230,6 @@ gtk_file_chooser_default_set_current_name (GtkFileChooser *chooser, _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), name); } -static void -select_func (GtkFileSystemModel *model, - GtkTreePath *path, - GtkTreeIter *iter, - gpointer user_data) -{ - GtkFileChooserDefault *impl = user_data; - GtkTreeSelection *selection; - - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view)); - - gtk_tree_selection_select_iter (selection, iter); -} - static gboolean gtk_file_chooser_default_select_file (GtkFileChooser *chooser, GFile *file, @@ -7429,7 +7265,7 @@ gtk_file_chooser_default_select_file (GtkFileChooser *chooser, files.data = (gpointer) file; files.next = NULL; - result = show_and_select_files (impl, parent_file, &files); + result = show_and_select_files (impl, &files); g_object_unref (parent_file); return result; } diff --git a/gtk/gtkfilechooserprivate.h b/gtk/gtkfilechooserprivate.h index 933bd86394..9f02b42e67 100644 --- a/gtk/gtkfilechooserprivate.h +++ b/gtk/gtkfilechooserprivate.h @@ -233,7 +233,6 @@ struct _GtkFileChooserDefault GSList *reload_icon_cancellables; GCancellable *file_list_drag_data_received_cancellable; GCancellable *update_current_folder_cancellable; - GCancellable *show_and_select_files_cancellable; GCancellable *should_respond_get_info_cancellable; GCancellable *file_exists_get_info_cancellable; GCancellable *update_from_entry_cancellable; diff --git a/gtk/gtkfilesystemmodel.c b/gtk/gtkfilesystemmodel.c index 300addf0e5..e2a7c4e544 100644 --- a/gtk/gtkfilesystemmodel.c +++ b/gtk/gtkfilesystemmodel.c @@ -968,11 +968,6 @@ gtk_file_system_model_got_files (GObject *object, GAsyncResult *res, gpointer da model->cancellable, gtk_file_system_model_closed_enumerator, NULL); - if (error) - g_error_free (error); - else - g_signal_emit (model, file_system_model_signals[FINISHED_LOADING], 0, NULL); - if (model->dir_thaw_source != 0) { g_source_remove (model->dir_thaw_source); @@ -980,6 +975,11 @@ gtk_file_system_model_got_files (GObject *object, GAsyncResult *res, gpointer da _gtk_file_system_model_thaw_updates (model); } + if (error) + g_error_free (error); + else + g_signal_emit (model, file_system_model_signals[FINISHED_LOADING], 0, NULL); + g_object_unref (model); } else @@ -1315,6 +1315,17 @@ _gtk_file_system_model_set_show_files (GtkFileSystemModel *model, } } +/** + * _gtk_file_system_model_get_cancellable: + * @model: the model + * + * Gets the cancellable used by the @model. This is the cancellable used + * internally by the @model that will be cancelled when @model is + * disposed. So you can use it for operations that should be cancelled + * when the model goes away. + * + * Returns: The cancellable used by @model + **/ GCancellable * _gtk_file_system_model_get_cancellable (GtkFileSystemModel *model) { @@ -1323,6 +1334,32 @@ _gtk_file_system_model_get_cancellable (GtkFileSystemModel *model) return model->cancellable; } +/** + * _gtk_file_system_model_get_is_visible: + * @model: the model + * @iter: a valid iterator + * + * Checks if the iterator is visible. A visible iterator references + * a row that is currently exposed using the #GtkTreeModel API. If + * the iterator is invisible, it references a file that is not shown + * for some reason, such as being filtered by the current filter or + * being a hidden file. + * + * Returns: %TRUE if the iterator is visible + **/ +gboolean +_gtk_file_system_model_get_is_visible (GtkFileSystemModel *model, + GtkTreeIter *iter) +{ + FileModelNode *node; + + g_return_val_if_fail (GTK_IS_FILE_SYSTEM_MODEL (model), FALSE); + g_return_val_if_fail (iter != NULL, FALSE); + + node = get_node (model, ITER_INDEX (iter)); + return node->visible; +} + /** * _gtk_file_system_model_get_info: * @model: a #GtkFileSystemModel @@ -1347,6 +1384,7 @@ _gtk_file_system_model_get_info (GtkFileSystemModel *model, FileModelNode *node; g_return_val_if_fail (GTK_IS_FILE_SYSTEM_MODEL (model), NULL); + g_return_val_if_fail (iter != NULL, NULL); node = get_node (model, ITER_INDEX (iter)); g_assert (node->info == NULL || G_IS_FILE_INFO (node->info)); @@ -1447,6 +1485,20 @@ node_get_for_file (GtkFileSystemModel *model, return 0; } +/** + * _gtk_file_system_model_get_iter_for_file: + * @model: the model + * @iter: the iterator to be initialized + * @file: the file to look up + * + * Initializes @iter to point to the row used for @file, if @file is part + * of the model. Note that upon successful return, @iter may point to an + * invisible row in the @model. Use + * _gtk_file_system_model_get_is_visible() to make sure it is visible to + * the tree view. + * + * Returns: %TRUE if file is part of the model and @iter was initialized + **/ gboolean _gtk_file_system_model_get_iter_for_file (GtkFileSystemModel *model, GtkTreeIter *iter, diff --git a/gtk/gtkfilesystemmodel.h b/gtk/gtkfilesystemmodel.h index 0ff4450054..aebc3c8d9c 100644 --- a/gtk/gtkfilesystemmodel.h +++ b/gtk/gtkfilesystemmodel.h @@ -53,6 +53,8 @@ GtkFileSystemModel *_gtk_file_system_model_new_for_directory(GFile * guint n_columns, ...); GCancellable * _gtk_file_system_model_get_cancellable (GtkFileSystemModel *model); +gboolean _gtk_file_system_model_get_is_visible (GtkFileSystemModel *model, + GtkTreeIter *iter); GFileInfo * _gtk_file_system_model_get_info (GtkFileSystemModel *model, GtkTreeIter *iter); gboolean _gtk_file_system_model_get_iter_for_file(GtkFileSystemModel *model, -- 2.30.2